From ee6939c833915bb5397fc8bcc84e1b5cd7c29c61 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 19 Sep 2006 11:13:10 +0100 Subject: [PATCH] [XEN] Fix the emulation of instructions in vm86 mode. It fetches them using cs and eip instead of only eip. This makes it at least possible to use the i945GM vesa bios from the running system. Signed-off-by: Bastian Blank --- xen/arch/x86/traps.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 07486ddcdd..01f5526b80 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1028,9 +1028,11 @@ static inline unsigned char inb_user( (admin_io_okay(_p, 4, _d, _r) ? outl(_v, _p) : ((void)0)) /* Instruction fetch with error handling. */ -#define insn_fetch(_type, _size, _ptr) \ -({ unsigned long _rc, _x; \ - if ( (_rc = copy_from_user(&_x, (_type *)eip, sizeof(_type))) != 0 ) \ +#define insn_fetch(_type, _size, cs, eip) \ +({ unsigned long _rc, _x, _ptr = eip; \ + if ( vm86_mode(regs) ) \ + _ptr += cs << 4; \ + if ( (_rc = copy_from_user(&_x, (_type *)_ptr, sizeof(_type))) != 0 ) \ { \ propagate_page_fault(eip + sizeof(_type) - _rc, 0); \ return EXCRET_fault_fixed; \ @@ -1040,7 +1042,7 @@ static inline unsigned char inb_user( static int emulate_privileged_op(struct cpu_user_regs *regs) { struct vcpu *v = current; - unsigned long *reg, eip = regs->eip, res; + unsigned long *reg, eip = regs->eip, cs = regs->cs, res; u8 opcode, modrm_reg = 0, modrm_rm = 0, rep_prefix = 0; unsigned int port, i, op_bytes = 4, data, rc; u32 l, h; @@ -1048,7 +1050,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) /* Legacy prefixes. */ for ( i = 0; i < 8; i++ ) { - switch ( opcode = insn_fetch(u8, 1, eip) ) + switch ( opcode = insn_fetch(u8, 1, cs, eip) ) { case 0x66: /* operand-size override */ op_bytes ^= 6; /* switch between 2/4 bytes */ @@ -1080,7 +1082,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) modrm_rm = (opcode & 1) << 3; /* REX.B */ /* REX.W and REX.X do not need to be decoded. */ - opcode = insn_fetch(u8, 1, eip); + opcode = insn_fetch(u8, 1, cs, eip); } #endif @@ -1162,7 +1164,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) case 0xe4: /* IN imm8,%al */ op_bytes = 1; case 0xe5: /* IN imm8,%eax */ - port = insn_fetch(u8, 1, eip); + port = insn_fetch(u8, 1, cs, eip); exec_in: if ( !guest_io_okay(port, op_bytes, v, regs) ) goto fail; @@ -1191,7 +1193,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) case 0xe6: /* OUT %al,imm8 */ op_bytes = 1; case 0xe7: /* OUT %eax,imm8 */ - port = insn_fetch(u8, 1, eip); + port = insn_fetch(u8, 1, cs, eip); exec_out: if ( !guest_io_okay(port, op_bytes, v, regs) ) goto fail; @@ -1240,7 +1242,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) goto fail; /* Privileged (ring 0) instructions. */ - opcode = insn_fetch(u8, 1, eip); + opcode = insn_fetch(u8, 1, cs, eip); switch ( opcode ) { case 0x06: /* CLTS */ @@ -1258,7 +1260,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) break; case 0x20: /* MOV CR?, */ - opcode = insn_fetch(u8, 1, eip); + opcode = insn_fetch(u8, 1, cs, eip); modrm_reg |= (opcode >> 3) & 7; modrm_rm |= (opcode >> 0) & 7; reg = decode_register(modrm_rm, regs, 0); @@ -1292,7 +1294,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) break; case 0x21: /* MOV DR?, */ - opcode = insn_fetch(u8, 1, eip); + opcode = insn_fetch(u8, 1, cs, eip); modrm_reg |= (opcode >> 3) & 7; modrm_rm |= (opcode >> 0) & 7; reg = decode_register(modrm_rm, regs, 0); @@ -1302,7 +1304,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) break; case 0x22: /* MOV ,CR? */ - opcode = insn_fetch(u8, 1, eip); + opcode = insn_fetch(u8, 1, cs, eip); modrm_reg |= (opcode >> 3) & 7; modrm_rm |= (opcode >> 0) & 7; reg = decode_register(modrm_rm, regs, 0); @@ -1342,7 +1344,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) break; case 0x23: /* MOV ,DR? */ - opcode = insn_fetch(u8, 1, eip); + opcode = insn_fetch(u8, 1, cs, eip); modrm_reg |= (opcode >> 3) & 7; modrm_rm |= (opcode >> 0) & 7; reg = decode_register(modrm_rm, regs, 0); -- 2.30.2